package org.zcode.generator.core.util;

import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.exception.ShellException;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.StringTokenizer;

import static org.mybatis.generator.internal.util.messages.Messages.getString;

/**
 * @author zhoulk
 * @Description:
 * @date: 2019/8/8
 */
public class GeneratorUtil {
    private static String nowDate;
    private static FullyQualifiedJavaType serializable = new FullyQualifiedJavaType("java.io.Serializable");
    private static FullyQualifiedJavaType lombok = new FullyQualifiedJavaType("lombok.Data");
    private static Random random = new Random();

    public static GeneratedJavaFile createEntity(IntrospectedTable introspectedTable, FullyQualifiedJavaType type, String target, String pack, String className, String remark, String author) {

        try {
            File directory = getDirectory(target, pack);
            File ipo = new File(directory, className);
            if (ipo.exists()) {
                System.out.println("入参类：" + ipo.getName() + "已存在");
                return null;
            }
        } catch (ShellException e) {
            e.printStackTrace();
            return null;
        }
        TopLevelClass ipoClass = new TopLevelClass(type);
        ipoClass.setVisibility(JavaVisibility.PUBLIC);
        ipoClass.addSuperInterface(serializable);
        ipoClass.addImportedType(serializable);
        ipoClass.addImportedType(lombok);
        ipoClass.addImportedType(new FullyQualifiedJavaType("java.util.Date"));
        ipoClass.addAnnotation("@Data");
        ipoClass.addJavaDocLine(getDocTmpl(remark, author));
        Field field = new Field();
        field.setName("serialVersionUID"); // 设置变量名
        FullyQualifiedJavaType fieldType = new FullyQualifiedJavaType("long");
        field.setType(fieldType); // 类型
        field.setVisibility(JavaVisibility.PRIVATE);
        field.setFinal(true);
        field.setStatic(true);
        field.setInitializationString("1L");
        ipoClass.addField(field);

        List<IntrospectedColumn> baseColumns = introspectedTable.getBaseColumns();
        List<IntrospectedColumn> columns = new ArrayList<>();
        if (introspectedTable.getPrimaryKeyColumns() != null){
            columns.addAll(0,introspectedTable.getPrimaryKeyColumns());
        }
        columns.addAll(baseColumns);
        for (IntrospectedColumn column : columns) {
            field = new Field();
            field.setName(column.getJavaProperty());
            field.setType(column.getFullyQualifiedJavaType());
            field.setVisibility(JavaVisibility.PRIVATE);
            field.addJavaDocLine("/**\n" +
                    "\t * " + column.getRemarks() + "\n" +
                    "\t */");
            ipoClass.addField(field);
        }
        return new GeneratedJavaFile(ipoClass, target);
    }

    public static String getDocTmpl(String remark, String author) {
        byte[] bytes = {(byte) 0xC2, (byte) 0xA0};
        String space;
        space = new String(bytes, StandardCharsets.UTF_8);
        return "/**\n" +
                space+"* @author: " + author + "\n" +
                space+"* @Description: " + remark + "\n" +
                space+"* @date: " + now() + "\n" +
                " */";
    }

    public static String getDocTmpl(String func, String param, String back, String desc, String author) {

        byte[] bytes = {(byte) 0xC2, (byte) 0xA0};
        String space;
        space = new String(bytes, StandardCharsets.UTF_8);
        space = space + space + space;
        return " " +
                "/** \n" +
                space + "* @Function: " + func + "\n" +
                space + "* @Description: " + desc + "\n" +
                space + "* @param: " + param + "\n" +
                space + "* @return: " + back + "\n" +
                space + "* @version: v1.0.0\n" +
                space + "* @author: " + author + "\n" +
                space + "* @date: " + now() + "\n" +
                space + "*\n" +
                space + "* Modification History:\n" +
                space + "* Date         author          Version            Description\n" +
                space + "*------------------------------------------------------*\n" +
                space + "* " + now() + "     " + author + "           v1.0.0             修改原因\n" +
                space + "*\n" +
                space + "*/";
    }

    public static String toLowerCase(String tableName) {
        StringBuilder sb = new StringBuilder(tableName);
        sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
        return sb.toString();
    }

    private static String now() {
        if (nowDate != null) {
            return nowDate;
        }
        Date now = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        nowDate = simpleDateFormat.format(now);
        return nowDate;
    }

    private static File getDirectory(String targetProject, String targetPackage) throws ShellException {
        return getFile(targetProject, targetPackage);
    }

    private static File getFile(String targetProject, String targetPackage) throws ShellException {
        System.out.println(System.getProperty("user.dir"));
        File project = new File(targetProject);
        if (!project.isDirectory()) {
            throw new ShellException(getString("Warning.9", //$NON-NLS-1$
                    targetProject));
        }
        StringBuilder sb = new StringBuilder();
        StringTokenizer st = new StringTokenizer(targetPackage, "."); //$NON-NLS-1$
        while (st.hasMoreTokens()) {
            sb.append(st.nextToken());
            sb.append(File.separatorChar);
        }

        File directory = new File(project, sb.toString());
        if (!directory.isDirectory()) {
            boolean rc = directory.mkdirs();
            if (!rc) {
                throw new ShellException(getString("Warning.10", //$NON-NLS-1$
                        directory.getAbsolutePath()));
            }
        }
        return directory;
    }

    public static String getTableRemarks(String tableRemarks) {
        if (StringUtils.isNotBlank(tableRemarks)) {
            if (tableRemarks.substring(tableRemarks.length() - 1).equals("表")) {
                tableRemarks = tableRemarks.substring(0, tableRemarks.length() - 1);
            }
        }
        return tableRemarks;
    }

    public static int randomInt() {
        return random.nextInt(89999) + 10000;
    }
}
